package com.nakamachizu.service;

import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.TimeZone;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slim3.datastore.Datastore;
import org.slim3.util.ThrowableUtil;

import com.google.appengine.api.datastore.GeoPt;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.urlfetch.HTTPResponse;
import com.google.appengine.api.urlfetch.URLFetchServiceFactory;
import com.nakamachizu.collection.LineDataSort;
import com.nakamachizu.model.LandMarkData;
import com.nakamachizu.model.LineData;
import com.nakamachizu.model.MapData;
import com.nakamachizu.model.MemberData;


public class StaticMapService {
    
    protected static final int BUFFER_SIZE = 1024;
    
    protected static final String LINE_WEIGHT = "5";
    
    protected static final String STATIC_MAPS_URL = "http://maps.google.com/staticmap";
    
    protected static final String CONTENT_GIF = "image/gif";
    
    protected static final String CONTENT_JPEG = "image/jpeg";
    
    public static void printErrorGif(HttpServletResponse response, HttpServletRequest request){

        try {
            StringBuffer buf = new StringBuffer("http://")
                                    .append(request.getServerName())
                                    .append(":")
                                    .append(request.getServerPort())
                                    .append("/icon/error.gif");
            URL url = new URL(buf.toString());
            HTTPResponse res = URLFetchServiceFactory.getURLFetchService().fetch(url);
            printGif(response, res.getContent());
        }catch(IOException e){
            ThrowableUtil.wrapAndThrow(e);
        }
    }
    
    public static void printOverFlowErrorGif(HttpServletResponse response, HttpServletRequest request, boolean isBig){

        try {
            StringBuffer buf = new StringBuffer("http://")
                                    .append(request.getServerName())
                                    .append(":")
                                    .append(request.getServerPort())
                                    .append("/icon/dataoverflow");
            if(isBig){
                buf.append("300.gif");
            }else{
                buf.append("120.gif");
            }
            URL url = new URL(buf.toString());
            HTTPResponse res = URLFetchServiceFactory.getURLFetchService().fetch(url);
            printGif(response, res.getContent());
        }catch(IOException e){
            ThrowableUtil.wrapAndThrow(e);
        }
    }
    
    public static void printGif(HttpServletResponse response, byte[] bytes){
        printImage(response, bytes, CONTENT_GIF);
    }
    
    public static void printJpeg(HttpServletResponse response, byte[] bytes){
        printImage(response, bytes, CONTENT_JPEG);
    }
    
    public static void printImage(HttpServletResponse response, byte[] bytes, String contentType){
        
        try {
            SimpleDateFormat fmt = new SimpleDateFormat("E, dd MMM yyyy hh:mm:ss zzz", Locale.US);
            fmt.setTimeZone(TimeZone.getTimeZone("GMT"));
            ByteArrayInputStream is = new ByteArrayInputStream(bytes);
            response.setContentType(contentType);
            response.setHeader("Content-Length", Integer.toString(bytes.length));
            response.setHeader("Expires", fmt.format(new Date()));
            response.setHeader("Pragma","no-cache");
            response.setHeader("Cache-Control","no-cache");
            
            OutputStream out =
                new BufferedOutputStream(response.getOutputStream());
            try {
                byte[] buf = new byte[BUFFER_SIZE];
                int length;
                while ((length = is.read(buf)) > 0) {
                    out.write(buf, 0, length);
                }
            } finally {
                out.flush();
                out.close();
            }
        } catch (IOException e) {
            ThrowableUtil.wrapAndThrow(e);
        }
    }
    
    public static URL getUrl(String apiKey, Key key, double centerLat, double centerLng, int zoomLevel, int width, int height, List<GeoPt>additional){
        
        MapData map = Datastore.get(MapData.class,  key);

        return getUrl(apiKey, map, centerLat, centerLng, zoomLevel, width, height, additional);
    }
    
    public static URL getUrl(String apiKey, MapData map, double centerLat, double centerLng, int zoomLevel, int width, int height, List<GeoPt>additional){
        URL result = null;
        StringBuffer buf = new StringBuffer(STATIC_MAPS_URL);
        buf.append("?center=").append(centerLat).append(",").append(centerLng);
        buf.append("&zoom=").append(zoomLevel);
        buf.append("&size=").append(width).append("x").append(height);
        buf.append("&maptype=mobile");
        buf.append("&key=").append(apiKey);
        buf.append("&sensor=false");
        //buf.append("&format=jpg");
        
        List<LandMarkData>lList = map.getLandMarkDataListRef().getModelList();
        List<MemberData>mList = map.getMemberDataListRef().getModelList();
        List<LineData>lineList = map.getLineDataListRef().getModelList();

        if(lineList != null && lineList.size() > 0){
            Collections.sort(lineList, new LineDataSort());
            String preGuid = "";
            GeoPt endPoint = new GeoPt(0.0f, 0.0f);
            String color = "";
            List<GeoPt>buffer = new ArrayList<GeoPt>();
            for(LineData line : lineList){
                if(!preGuid.equals(line.getGuid()) || endPoint.compareTo(line.getStart()) != 0){
                    preGuid = line.getGuid();
                    if(buffer.size() > 0){
                        buf.append("&path=rgb:")
                        .append(color)
                        .append(",weight:").append(LINE_WEIGHT).append("|");
                        for(GeoPt geo : buffer){
                            buf.append(geo.getLatitude())
                            .append(",")
                            .append(geo.getLongitude())
                            .append("|");
                        }
                    }
                    buffer = new ArrayList<GeoPt>();
                    buffer.add(line.getStart());
                    buffer.add(line.getEnd());
                    color = line.getColor();
                    preGuid = line.getGuid();
                    endPoint = line.getEnd();
                    
                }else{
                    if(endPoint.compareTo(line.getStart()) == 0){
                        buffer.add(line.getEnd());
                    }else{
                        buffer.add(line.getStart());
                        buffer.add(line.getEnd());
                    }
                    endPoint = line.getEnd();
                }
                /*
                buf.append("&path=rgb:")
                .append(line.getColor())
                .append(",weight:5|")
                .append(line.getStart().getLatitude())
                .append(",")
                .append(line.getStart().getLongitude())
                .append("|")
                .append(line.getEnd().getLatitude())
                .append(",")
                .append(line.getEnd().getLongitude());
                */
            }
            if(buffer.size() > 0){
                buf.append("&path=rgb:")
                .append(color)
                .append(",weight:").append(LINE_WEIGHT).append("|");
                for(GeoPt geo : buffer){
                    buf.append(geo.getLatitude())
                    .append(",")
                    .append(geo.getLongitude())
                    .append("|");
                }
                buffer = new ArrayList<GeoPt>();
            }
        }
        
        buf.append("&markers=");
        
        if(additional  != null){
            for(GeoPt pt : additional){
                buf.append(pt.getLatitude());
                buf.append(",");
                buf.append(pt.getLongitude());
                buf.append(",");
                buf.append("blue");
                buf.append("|");
            }
        }
        
        if(lList != null){
            for(LandMarkData data : lList){
                buf.append(data.getLatLng().getLatitude());
                buf.append(",");
                buf.append(data.getLatLng().getLongitude());
                buf.append(",");
                buf.append(data.getMIconName());
                buf.append("|");
            }
        }
        
        if(mList != null){
            for(MemberData data : mList){
                buf.append(data.getLatLng().getLatitude());
                buf.append(",");
                buf.append(data.getLatLng().getLongitude());
                buf.append(",");
                buf.append(data.getMIconName());
                buf.append("|");
            }
        }
        
        try{
            //System.out.println(buf.toString());
            result = new URL(buf.toString());
        }catch(MalformedURLException e){
            e.printStackTrace();
        }
        return result;
    }

}
